#!/usr/bin/env python
"""This module is the core program behind JamesTheBot. Most of the actual
logic behind any code process will be in the plugins folder.

This file is copyright Simon Johnson 2008 and is licensed under the GPL V2."""
import socket
import os
def main():
	"""This routine is the entry point for the program. It handles 
	connecting to the server and periodically ponging back to the
	server's ping. It delegates the handling of IRC events to 
	sub-ordinate methods."""
	
	print "Connecting to irc.incognitus.net"
	network = 'irc.incognitus.net'
	port = 6667
	irc = socket.socket ( socket.AF_INET, socket.SOCK_STREAM )
	irc.connect ( ( network, port ) )
	irc.send ( 'NICK JamesTheBot\r\n' )
	irc.send ( 'USER James The Bot :JamesTheBot\r\n' )
	irc.send ( 'JOIN #Bots \r\n')
	while True:
		data = irc.recv ( 4096 )
		if data.find ( 'PING' ) != -1:
			irc.send ( 'PONG ' + data.split() [ 1 ] + '\r\n' )
		lines = data.split("\r\n")
		for line in lines:
			raise_event(line, irc)
		print data		

def get_plugins():
	""" This routine gets the plugins from the plugins folder and imports
	 them. A reload is also done so that any changes to the plugins are
	 loaded in to memory."""
	modules = []
	for pluginfile in os.listdir('Plugins'):
		if pluginfile.endswith("py"):
			modulename = "Plugins." +  file[:-3]
			if modulename != "Plugins.__init__":
				print modulename
				exec ("import " + modulename)
				exec("modules.append(reload(" + modulename + "))")
	return modules
			
def get_routine(module, routinename):
	"""This routine reflects the passed in module and looks for a method 
	called "routineName". If it finds it, the method itself is returned. 
	If it can't, it returns None."""
	
	if routinename in module.__dict__:
		return module.__dict__[routinename]
	else:
		return None
	
def raise_channel_event(module, routinename, arguments):
	"""This routine parses the text event passed in from "arguments" 
	parameter and calls the "routineName" found within the "module"
	argument. Assuming the routine is found, it is then called using
	the typical calling convention for channel messages."""
	
	function = get_routine(module, routinename)
	if (function != None):
		textevent = arguments["textEvent"]
		datafragments = textevent.split(' ')
		author = datafragments[0]
		target = datafragments[2]
		message = datafragments[3][1:]
		function(arguments["irc"], author, target, message)
	
def raise_change_mode(module, routinename, arguments):
	"""This routine parses the text event passed in from the "arguments" 
	parameter and uses it to fire a "ChangeMode" event. It does this by
	finding the routine specified by the "routineName" parameter in the
	module specified by the "module" parameter. It then calls this 
	routine with the calling convention for mode changes."""
	
	irc = arguments["irc"]
	textevent = arguments["textEvent"]
	function = get_routine(module, routinename)
	
	if (function != None):
		datafragments = textevent.split(' ')
		sourcenick = datafragments[0]
		channel = datafragments[2]
		targetnick = datafragments[4]
		function(irc, sourcenick, targetnick, channel)

def raise_event(textevent, irc):
	"""This routine goes through all the loaded plugins and 
	works out whether it needs to trigger an event on that plugin."""
	datafragments = textevent.split(' ')
	
	if len(datafragments) < 2:
		return
	
	action = datafragments[1]
	
	try:
		plugins = get_plugins()
		
		arguments = {"irc": irc, "textEvent": textevent} 
		for plugin in plugins:
			if (action == "PRIVMSG"):
				raise_channel_event(plugin, "handle_priv_msg", arguments)
			elif (action =="JOIN"):	
				raise_channel_event(plugin, "handle_join", arguments)
			elif (action=="TOPIC"):
				raise_channel_event(plugin, "handle_topic_change", arguments)
			elif (action=="MODE"):
				modechange = datafragments[3][0:2]
				if modechange == "+o":
					raise_change_mode(plugin, "handle_op", arguments)
				if modechange == "-o":
					raise_change_mode(plugin, "handle_deop", arguments)
				if modechange == "+v":
					raise_change_mode(plugin, "handle_voice", arguments)
				if modechange == "-v":
					raise_change_mode(plugin, "handle_devoice", arguments)

			raise_channel_event(plugin, "HandleRaw", arguments)
	except RuntimeError:
		print "An error occurred while trying to raise an event."

if __name__ == "__main__":
	main()